﻿using DataVirtualization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using TinyIoC;
using WinDataInspector.Provider;
using WinDataInspector.Interfaces;
using WinDataInspector.Model;
using WinLogAnalyzer.Naming;
using System.Text.RegularExpressions;

namespace WinDataInspector.ViewModel
{
    public enum ListTypes { Byte, Int16, Int32, Int64, Single, Double, String }

    class MainVM : BaseViewModel
    {
        #region Fields

        DataInspector.DataInspector inspector; 
        
        #endregion

        #region Constructor

        public MainVM()
        {
            var container = TinyIoCContainer.Current;

            if (!Utility.Utility.IsDesignMode())
            {    
            }
        }

        #endregion

        #region Properties

        private string inputAddress;

        public string InputAddress
        {
            get { return inputAddress; }
            set {
                inputAddress = value;
                RaisePropertyChanged(() => InputAddress);
            }
        }


        private bool isProcessing;

        public bool IsProcessing
        {
            get { return isProcessing; }
            set {
                isProcessing = value;
                RaisePropertyChanged(() => IsProcessing);
            }
        }


        private string status;

        public string Status
        {
            get { return status; }
            set {
                status = value;
                RaisePropertyChanged(() => Status);
            }
        }


        private int selectedIndexData;

        public int SelectedIndexData
        {
            get { return selectedIndexData; }
            set {
                selectedIndexData = value;
                RaisePropertyChanged(() => SelectedIndexData);
            }
        }


        private ListTypes dataTypeSelected;

        public ListTypes DataTypeSelected
        {
            get { return dataTypeSelected; }
            set {
                dataTypeSelected = value;
                RaisePropertyChanged(() => DataTypeSelected);
            }
        }


        private string searchInput;

        public string SearchInput
        {
            get { return searchInput; }
            set {
                searchInput = value;
                RaisePropertyChanged(() => SearchInput);
            }
        }


        private long fileSize;

        public long FileSize
        {
            get { return fileSize; }
            set {
                fileSize = value;
                RaisePropertyChanged(() => FileSize);
            }
        }


        private string filename;

        public string Filename
        {
            get { return filename; }
            set
            {
                filename = value;
                RaisePropertyChanged(() => Filename);
            }
        }

        private AsyncVirtualizingCollection<HexItem> data;

        public AsyncVirtualizingCollection<HexItem> Data
        {
            get { return data; }
            set
            {
                data = value;
                RaisePropertyChanged(() => Data);
            }
        }

        private IList<HexItem> hexData;

        public IList<HexItem> HexData
        {
            get { return hexData; }
            set
            {
                hexData = value;
                RaisePropertyChanged(() => HexData);
            }
        }

        private long position;

        public long Position
        {
            get { return position; }
            set {
                position = value;
                RaisePropertyChanged(() => Position);
            }
        }


        #endregion

        #region Actions

        public Action<int> ScrollToLineAction { get; set; }

        #endregion

        #region EventHandler

        public event EventHandler ShowMessageEvent;
        
        #endregion

        #region Methods

        bool CanJumpLine()
        {
            if (inputAddress == null)
                return false;

            inputAddress = Regex.Replace(inputAddress, "^0[xX]", String.Empty);

            int line = (int.Parse(inputAddress, System.Globalization.NumberStyles.HexNumber) / 16);

            int numlines = (int)(fileSize >> 4);

            if (line >= numlines)
                return false;

            return true;
        }

        void JumpLine()
        {
            inputAddress = Regex.Replace(inputAddress, "^0[xX]", String.Empty);

            int line = (int.Parse(inputAddress, System.Globalization.NumberStyles.HexNumber) / 16);

            //ScrollToLineAction(line);
            this.SelectedIndexData = line;
        }

        void ProcessData(string filename)
        {
            var container = TinyIoCContainer.Current;

            if (this.inspector != null)
                this.inspector.Dispose();

            this.inspector = container.Resolve<DataInspector.DataInspector>(ContainerNSR.DATA_INSPECTOR, new NamedParameterOverloads(new Dictionary<string, object>()
                {
                    {
                        "filename", filename
                    }
                }));

            long filesize = new System.IO.FileInfo(filename).Length;
            
            // create the demo items provider according to specified parameters
            int numItems = (int)Math.Ceiling((double)filesize / 16);
            HexProvider hexProvider = new HexProvider(inspector, numItems);

            // create the collection according to specified parameters
            int pageSize = 1000;
            int pageTimeout = 30;

            this.Data = new AsyncVirtualizingCollection<HexItem>(hexProvider, pageSize, pageTimeout * 1000);

            //this.HexData = new List<HexItem>(hexProvider.FetchRange(0, hexProvider.FetchCount()));

            this.Filename = filename;

            this.FileSize = filesize;
        }

        void OpenFile()
        {
            var container = TinyIoCContainer.Current;

            IDialogFileService service = container.Resolve<IDialogFileService>(ContainerNSR.DLG_OPEN_LOG_FILE);

            string filename = service.OpenFile();

            if (String.IsNullOrEmpty(filename) == false)
            {
                ProcessData(filename);
            }
        }

        void SearchValue()
        {
            byte[] data;

            try
            {
                switch (dataTypeSelected)
                {
                    case ListTypes.Byte:
                        data = new byte[1] { Byte.Parse(searchInput) };
                        break;
                    case ListTypes.Int16:
                        data = BitConverter.GetBytes(Int16.Parse(searchInput));
                        break;
                    case ListTypes.Int32:
                        data = BitConverter.GetBytes(Int32.Parse(searchInput));
                        break;
                    case ListTypes.Int64:
                        data = BitConverter.GetBytes(Int64.Parse(searchInput));
                        break;
                    case ListTypes.Single:
                        data = BitConverter.GetBytes(Single.Parse(searchInput));
                        break;
                    case ListTypes.Double:
                        data = BitConverter.GetBytes(Double.Parse(searchInput));
                        break;
                    case ListTypes.String:
                        data = System.Text.Encoding.UTF8.GetBytes(searchInput);
                        break;
                    default:
                        data = System.Text.Encoding.UTF8.GetBytes(searchInput);
                        break;
                }

                this.inspector.Stream.Position = this.position;

                long index = this.inspector.Find(data, null);

                System.Diagnostics.Debug.WriteLine("Position: " + index);

            }
            catch (Exception e)
            {
                ShowMessageEvent(this, new MessageEventArgs { Message = e.Message, Title = "Search input error" } );
            }
            

            
        }

        #endregion

        #region Commands

        public ICommand OpenFileCommand { get { return new MvvmFoundation.Wpf.RelayCommand(OpenFile); } }
        public ICommand SearchValueCommand { get { return new MvvmFoundation.Wpf.RelayCommand(SearchValue); } }
        public ICommand JumpLineCommand { get { return new MvvmFoundation.Wpf.RelayCommand(JumpLine, CanJumpLine); } }

        #endregion
    }
}
